/**
 * Copyright (c) 2006-2017, JGraph Ltd
 * Copyright (c) 2006-2017, Gaudenz Alder
 */
import mxgraph from './index';
const {
  mxEvent,
  mxUtils,
  mxResources,
} = mxgraph;

import DrawioFile from './DrawioFile'
/**
 * Constructs a new point for the optional x and y coordinates. If no
 * coordinates are given, then the default values for <x> and <y> are used.
 * @constructor
 * @class Implements a basic 2D point. Known subclassers = {@link mxRectangle}.
 * @param {number} x X-coordinate of the point.
 * @param {number} y Y-coordinate of the point.
 */
const StorageFile = function (ui, data, title) {
  DrawioFile.call(this, ui, data);

  this.title = title;
};

//Extends mxEventSource
mxUtils.extend(StorageFile, DrawioFile);

/**
 * Sets the delay for autosave in milliseconds. Default is 2000.
 */
StorageFile.prototype.autosaveDelay = 2000;

/**
 * Sets the delay for autosave in milliseconds. Default is 20000.
 */
StorageFile.prototype.maxAutosaveDelay = 20000;

/**
 * A differentiator of the stored object type (file or lib)
 */
StorageFile.prototype.type = 'F';

/**
 * Translates this point by the given vector.
 * 
 * @param {number} dx X-coordinate of the translation.
 * @param {number} dy Y-coordinate of the translation.
 */
StorageFile.prototype.getMode = function () {
  //   return App.MODE_BROWSER;
  return 'browser'
};

/**
 * Overridden to enable the autosave option in the document properties dialog.
 */
StorageFile.prototype.isAutosaveOptional = function () {
  return true;
};

/**
 * Translates this point by the given vector.
 * 
 * @param {number} dx X-coordinate of the translation.
 * @param {number} dy Y-coordinate of the translation.
 */
StorageFile.prototype.getHash = function () {
  return 'L' + encodeURIComponent(this.getTitle());
};

/**
 * Translates this point by the given vector.
 * 
 * @param {number} dx X-coordinate of the translation.
 * @param {number} dy Y-coordinate of the translation.
 */
StorageFile.prototype.getTitle = function () {
  return this.title;
};

/**
 * Translates this point by the given vector.
 * 
 * @param {number} dx X-coordinate of the translation.
 * @param {number} dy Y-coordinate of the translation.
 */
StorageFile.prototype.isRenamable = function () {
  return true;
};

/**
 * Translates this point by the given vector.
 * 
 * @param {number} dx X-coordinate of the translation.
 * @param {number} dy Y-coordinate of the translation.
 */
StorageFile.prototype.save = function (revision, success, error) {
  this.saveAs(this.getTitle(), success, error);
};

/**
 * Translates this point by the given vector.
 * 
 * @param {number} dx X-coordinate of the translation.
 * @param {number} dy Y-coordinate of the translation.
 */
StorageFile.prototype.saveAs = function (title, success, error) {
  DrawioFile.prototype.save.apply(this, arguments);
  this.saveFile(title, false, success, error);
};


StorageFile.getFileContent = function (ui, title, success, error) {
  ui.getDatabaseItem(title, function (obj) {
      success(obj != null ? obj.data : null);
    },
    mxUtils.bind(this, function () {
      if (ui.database == null) //fallback to localstorage
      {
        ui.getLocalData(title, success);
      } else if (error != null) {
        error();
      }
    }), 'files');
};

StorageFile.getFileInfo = function (ui, title, success, error) {
  ui.getDatabaseItem(title, function (obj) {
      success(obj);
    },
    mxUtils.bind(this, function () {
      if (ui.database == null) //fallback to localstorage
      {
        ui.getLocalData(title, function (data) {
          success(data != null ? {
            title: title
          } : null);
        });
      } else if (error != null) {
        error();
      }
    }), 'filesInfo');
};

/**
 * Translates this point by the given vector.
 * 
 * @param {number} dx X-coordinate of the translation.
 * @param {number} dy Y-coordinate of the translation.
 */
StorageFile.prototype.saveFile = function (title, revision, success, error) {
  if (!this.isEditable()) {
    if (success != null) {
      success();
    }
  } else {
    var fn = mxUtils.bind(this, function () {
      if (this.isRenamable()) {
        this.title = title;
      }

      try {
        var saveDone = mxUtils.bind(this, function () {
          this.setModified(false);
          this.contentChanged();

          if (success != null) {
            success();
          }
        });

        var data = this.getData();

        this.ui.setDatabaseItem(null, [{
          title: this.title,
          size: data.length,
          lastModified: Date.now(),
          type: this.type
        }, {
          title: this.title,
          data: data
        }], saveDone, mxUtils.bind(this, function () {
          if (this.ui.database == null) //fallback to localstorage
          {
            this.ui.setLocalData(this.title, data, saveDone);
          } else if (error != null) {
            error();
          }
        }), ['filesInfo', 'files']);
      } catch (e) {
        if (error != null) {
          error(e);
        }
      }
    });

    // Checks for trailing dots
    if (this.isRenamable() && title.charAt(0) == '.' && error != null) {
      error({
        message: mxResources.get('invalidName')
      });
    } else {
      StorageFile.getFileInfo(this.ui, title, mxUtils.bind(this, function (data) {
        if (!this.isRenamable() || this.getTitle() == title || data == null) {
          fn();
        } else {
          this.ui.confirm(mxResources.get('replaceIt', [title]), fn, error);
        }
      }), error);
    }
  }
};

/**
 * Translates this point by the given vector.
 * 
 * @param {number} dx X-coordinate of the translation.
 * @param {number} dy Y-coordinate of the translation.
 */
StorageFile.prototype.rename = function (title, success, error) {
  var oldTitle = this.getTitle();

  if (oldTitle != title) {
    StorageFile.getFileInfo(this.ui, title, mxUtils.bind(this, function (data) {
      var fn = mxUtils.bind(this, function () {
        this.title = title;

        // Updates the data if the extension has changed
        if (!this.hasSameExtension(oldTitle, title)) {
          this.setData(this.ui.getFileData());
        }

        this.saveFile(title, false, mxUtils.bind(this, function () {
          this.ui.removeLocalData(oldTitle, success);
        }), error);
      });

      if (data != null) {
        this.ui.confirm(mxResources.get('replaceIt', [title]), fn, error);
      } else {
        fn();
      }
    }), error);
  } else {
    success();
  }
};

/**
 * Returns the location as a new object.
 * @type mx.Point
 */
StorageFile.prototype.open = function () {
  DrawioFile.prototype.open.apply(this, arguments);

  // Immediately creates the storage entry
  this.saveFile(this.getTitle());
};

/**
 * Adds the listener for automatically saving the diagram for local changes.
 */
StorageFile.prototype.getLatestVersion = function (success, error) {
  StorageFile.getFileContent(this.ui, this.title, mxUtils.bind(this, function (data) {
    success(new StorageFile(this.ui, data, this.title));
  }), error);
};

/**
 * Stops any pending autosaves and removes all listeners.
 */
StorageFile.prototype.destroy = function () {
  DrawioFile.prototype.destroy.apply(this, arguments);

  if (this.storageListener != null) {
    mxEvent.removeListener(window, 'storage', this.storageListener);
    this.storageListener = null;
  }
};

StorageFile.listLocalStorageFiles = function (type) {
  var filesInfo = [];

  for (var i = 0; i < localStorage.length; i++) {
    var key = localStorage.key(i);
    var value = localStorage.getItem(key);

    if (key.length > 0 && key.charAt(0) != '.' && value.length > 0) {
      var isFile = (type == null || type == 'F') && (value.substring(0, 8) === '<mxfile ' ||
        value.substring(0, 5) === '<?xml' || value.substring(0, 12) === '<!--[if IE]>');
      var isLib = (type == null || type == 'L') && (value.substring(0, 11) === '<mxlibrary>');

      if (isFile || isLib) {
        filesInfo.push({
          title: key,
          type: isFile ? 'F' : 'L',
          size: value.length,
          lastModified: Date.now()
        });
      }
    }
  }

  return filesInfo;
};

StorageFile.migrate = function (db) {
  var lsFilesInfo = StorageFile.listLocalStorageFiles();
  lsFilesInfo.push({
    title: '.scratchpad',
    type: 'L'
  }); //Adding scratchpad also since it is a library (storage file)
  var tx = db.transaction(['files', 'filesInfo'], 'readwrite');
  var files = tx.objectStore('files');
  var filesInfo = tx.objectStore('filesInfo');

  for (var i = 0; i < lsFilesInfo.length; i++) {
    var lsFileInfo = lsFilesInfo[i];
    var data = localStorage.getItem(lsFileInfo.title);
    files.add({
      title: lsFileInfo.title,
      data: data
    });
    filesInfo.add(lsFileInfo);
  }
};

StorageFile.listFiles = function (ui, type, success, error) {
  ui.getDatabaseItems(function (filesInfo) {
    var files = [];

    if (filesInfo != null) {
      for (var i = 0; i < filesInfo.length; i++) {
        if (filesInfo[i].title.charAt(0) != '.' && (type == null || filesInfo[i].type == type)) {
          files.push(filesInfo[i]);
        }
      }
    }

    success(files);
  }, function () {
    if (ui.database == null) //fallback to localstorage
    {
      success(StorageFile.listLocalStorageFiles(type));
    } else if (error != null) {
      error();
    }
  }, 'filesInfo');
};

StorageFile.deleteFile = function (ui, title, success, error) {
  ui.removeDatabaseItem([title, title], success, function () {
    if (ui.database == null) //fallback to localstorage
    {
      localStorage.removeItem(title)
      success();
    } else if (error != null) {
      error();
    }
  }, ['files', 'filesInfo']);
};

export default StorageFile